import java.util.Iterator;
import java.util.LinkedList;
import java.io.*;
import java.util.Scanner;

public class Calendar {
	private static final int WAITTIME=15; //the minimum time between appointments 

	private LinkedList<Appointment> approved;

	private LinkedList<Appointment> pending;

	/**
	 * Initializes the calendar with empty appointment lists.
	 */
	public Calendar(){
		approved = new LinkedList<Appointment>();
		pending = new LinkedList<Appointment>();
	}
	
	public String getStats()
	{
		return "Number of Approved Appointments: " + 
		approved.size() + "\nNumber of Pending Appointments: " + pending.size();
	}
	
	/**
	 * Adds a new appointment to the pending appointment list.
	 * @param newAppointment
	 */
	public void addAppointment(Appointment newAppointment){
		pending.add(newAppointment);
	}

	public Appointment getPendingAppointment(String a)
	{
		Iterator<Appointment> aiterator = pending.iterator();
		Appointment cur;
		while(aiterator.hasNext())
		{
			cur = aiterator.next();
			if(cur.requester != null && cur.requester.userID.equals(a))
			return cur;
		}
		return null;
	}
	
	public Appointment getApprovedAppointment(String a)
	{
		Iterator<Appointment> aiterator = approved.iterator();
		Appointment cur;
		while(aiterator.hasNext())
		{
			cur = aiterator.next();
			if(cur.requester != null && cur.requester.userID.equals(a))
			return cur;
		}
		return null;
	}
	/**
	 * Checks for a conflict within the approved appointments.
	 * @param appointment
	 * @return 
	 */
	public boolean isConflict(Appointment appointment){
		for (Appointment a: approved){
			if (a.getDoctor().compareTo(appointment.getDoctor()) ==  0){
				if (a.getYear() == appointment.getYear()){
					if (a.getMonth() == appointment.getMonth()){
						if (a.getDay() == appointment.getDay()){
							if (a.getMinute() - appointment.getMinute() > a.getLength()+WAITTIME ||
									appointment.getMinute() -a.getMinute() > appointment.getLength() + WAITTIME){		
								return true;
							}
						}
					}
				}
			}
		}
		return false;
	}

	/**
	 * Checks the pending appointments for any approvals.
	 * It moves any approved appointments over to the
	 * approved list.
	 */
	public void update(){
		int i=0;
		while(i < pending.size()){
			if (pending.get(i).isApproved()){
				if (!isConflict(pending.get(i))){
					approved.add(pending.remove(i));
					i--;
				}
			}
			i++;
		}
	}

	/**
	 * Gets the appointments for a day.
	 * @param day	The day
	 * @param month	The month
	 * @param year	The year
	 * @return a list of all the appointments at the respective date
	 */
	public LinkedList<Appointment> getAppointments(int day, int month, int year){
		LinkedList<Appointment> appointments= new LinkedList<Appointment>();
		for (Appointment a: approved){
			if (a.getDay() == day){
				if (a.getMonth() == month){
					if (a.getYear() == year){
						appointments.add(a);
					}
				}
			}
		}
		return appointments;
	}

	/**
	 * Removes an appointment from the calendar.
	 * @param toBeRemoved	the appointment to be removed. MUST
	 * 						be the actual appointment object.
	 * @return	the removed appointment, null if not found.
	 */
	public Appointment removeAppointment(Appointment toBeRemoved){
		int i=0;
		while(i < pending.size()){
			if (pending.get(i) == toBeRemoved){
				return pending.remove(i);
			}
			i++;
		}
		i=0;
		while(i<approved.size()){
			if (approved.get(i)==toBeRemoved){
				return approved.remove(i);
			}
			i++;
		}
		return null;
	}
	public String processAppointment(String s1, String s2)
	{
		Appointment a;
		if(Integer.valueOf(s2) == 0)
		{
			a = getPendingAppointment(s1);
			if(a == null)
			a = getApprovedAppointment(s1);
			if(a == null)
			return "-1";
			
			DatabaseUsers.getUser(Integer.valueOf(s1)).apptreq = "0";
			removeAppointment(a);
			
		}
		else
		{
			a = getPendingAppointment(s1);
			if(a==null)
			return "-1";
			a.approve();
			update();
		}
		return "0";
	}

	/**
	 * @return All of the unapproved appointments
	 */
	public LinkedList<Appointment> getAppointmentRequests(){
		return pending;
	}
	
	public LinkedList<Appointment> getApprovedAppointments(){
		return approved;
	}
	
	public String toString(){
		String s="";
//		for (Appointment a: pending){
//			s+=a.toString() + "\n";
//		}
//		s+="\n";
		for (Appointment a: approved){
			s+=a.toString() + "\n";
		}
		return s;
	}
	public String toStringTotal(){
		String s="";
		for (Appointment a: pending){
			s+=a.toString() + "\r\n";
		}
		if(pending.size() == 0)
			s+="\r\n";
		
		s+="\r\n";
		for (Appointment a: approved){
			s+=a.toString() + "\r\n";
		}
		return s;
	}
	
	public String pendingString(){
		String s="";
		for (Appointment a: pending){
			s+=a.toString() + "\n";
		}
//		s+="\n";
//		for (Appointment a: approved){
//			s+=a.toString() + "\n";
//		}
		return s;
	}
	/**
	 * 
	 * @param calendar
	 */
	public Calendar(String calendar){
		approved = new LinkedList<Appointment>();
		pending = new LinkedList<Appointment>();
		if(!calendar.equals(""))
		{
		try{
			String[] lists = calendar.split("\r\n\r\n");
			String[] args = lists[0].split("\r\n");
			
			Appointment temp;
			for (String s: args){
				temp=Appointment.fromString(s);
				if (temp!=null) pending.add(temp);
			}
			if(lists.length > 1)
			{
			args = lists[1].split("\r\n");
			for (String s: args){
				temp=Appointment.fromString(s);
				if (temp!=null) approved.add(temp);
			}
			}
		}
		catch(Exception e){
			System.out.println("Error parsing calendar");
			e.printStackTrace();
		}
		}
	}
	
	public static Calendar loadCalendar(){
		Scanner reader;
		try{
			reader = new Scanner(new File("src/calendar.txt"));
		}
		catch(Exception e){
			System.out.println("Unable to load file");
			Logger.log("Unable to load file");
			return new Calendar("");
		}
		String s="";
		while (reader.hasNextLine()){
			s+=reader.nextLine()+"\r\n";
		}
		Calendar cal = new Calendar(s);
		return cal;
	}
	public void saveCalendar(){
		FileWriter writer;
		try{
			writer = new FileWriter(new File("src/calendar.txt"));
		}
		catch(Exception e){
			System.out.println("Error opening file to write.");
			Logger.log("Error opening file to write.");
			return;
		}
		try {
			writer.write(toStringTotal());
			writer.close();
		} 
		catch (IOException e) {
			System.out.println("Error writing to file");
			Logger.log("Error writing to file");
		}
	}
	
	public String requestAppointment(String s1, String s2, String s3, String s4,
			String s5, String s6, String s7)
	{
		if(DatabaseUsers.getUser(Integer.valueOf(s1)).apptreq.equals("1"))
			return "-1";
		Appointment appt = new Appointment(s2, s3, Integer.valueOf(s4), 
				Integer.valueOf(s5), Integer.valueOf(s6), Integer.valueOf(s7),
				DatabaseUsers.getUser(Integer.valueOf(s1)));
		DatabaseUsers.getUser(Integer.valueOf(s1)).apptreq = "1";
		this.addAppointment(appt);
		return "0";
	}//end requestappointment
}
